package algorithm_demo.demo03;

/**
 * 是否平衡二叉树
 * 给定一棵二叉树的头节点head，返回这颗二叉树是不是平衡二叉树。
 * 平衡二叉树：每一棵子树的左树高度和右树高度的差值不超过1
 * 对于每棵树的头X，满足以下三点即为平衡二叉树
 * 1 ） X的左子树是平衡二叉树
 * 2 )  X的右子树的平衡二叉树
 * 3 ） X的左子树高度 - 右子树高度 绝对值小于2(小于等于1)
 *
 * @author Api
 * @date 2023/2/12 3:29
 */
public class Code01_IsBalanced {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    public static class Info {
        public boolean isBalanced;
        public int height;

        public Info() {

        }

        public Info(boolean isBalanced, int height) {
            this.isBalanced = isBalanced;
            this.height = height;
        }
    }


    public static boolean isBalanced(Node head) {
        return process(head).isBalanced;
    }

    public static Info process(Node head) {
        if (head == null) {
            return new Info(true, 0);
        }
        Info leftInfo = process(head.left);
        Info rightInfo = process(head.right);
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;//组装Info
        boolean isBalanced = true;
        if (!leftInfo.isBalanced || !rightInfo.isBalanced){
            isBalanced = false;
        }
        if (Math.abs(leftInfo.height - rightInfo.height) > 1){
            isBalanced = false;
        }
        return new Info(isBalanced, height);
    }

    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static Node generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }

    public static void main(String[] args) {
//        int maxLevel = 5;
//        int maxValue = 100;
//        int testTimes = 1000000;
//        for (int i = 0; i < testTimes; i++) {
//            Node head = generateRandomBST(maxLevel, maxValue);
//            if (isBalanced1(head) != isBalanced(head)) {
//                System.out.println("Oops!");
//            }
//        }

        Node root = new Node(5);
        root.left = new Node(3);
        root.right = new Node(7);
        root.left.left = new Node(1);
        root.left.right = new Node(4);
        root.left.left.left = new Node(0);
        root.left.left.right = new Node(2);
        root.right.left = new Node(6);
        root.right.right = new Node(8);
        root.right.right.right = new Node(9);

        boolean balanced = isBalanced(root);
        System.out.println(balanced);
    }

    public static boolean isBalanced1(Node head) {
        boolean[] ans = new boolean[1];
        ans[0] = true;
        process1(head, ans);
        return ans[0];
    }

    public static int process1(Node head, boolean[] ans) {
        if (!ans[0] || head == null) {
            return -1;
        }
        int leftHeight = process1(head.left, ans);
        int rightHeight = process1(head.right, ans);
        if (Math.abs(leftHeight - rightHeight) > 1) {
            ans[0] = false;
        }
        return Math.max(leftHeight, rightHeight) + 1;
    }
}
